package com.artfii.fluentsql.core.jdbc;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import com.artfii.fluentsql.core.tools.Pair;

/**
 * Func:   : connection 选择策略
 *
 * @author : Lqf(leeton)
 * @date : 2021/11/1.
 */
public abstract class ConnectionUsedStrategy {

    abstract Number get();
    private static ConnectionUsedStrategy strategy = null;

    public static ConnectionUsedStrategy build() {
        if (null == strategy) {
            List<Pair<String, Integer>> list;
            list = getSlaveList();
            strategy = new WeightRandomStrategy(list);
        }
        return strategy;
    }

    private static List<Pair<String, Integer>> getSlaveList() {
        List<Pair<String, Integer>> list = new ArrayList<>();
        List<FluentSqlConfig.DataSourceConfig> dataSourceConfigList = FluentSqlConfig.default_config.getSlaveConfigList();
        if (dataSourceConfigList.size() > 0) {
            for (FluentSqlConfig.DataSourceConfig dataSourceConfig : dataSourceConfigList) {
                list.add(new Pair(dataSourceConfig.getId(), dataSourceConfig.getWeight_rate()));
            }
        }
        return list;
    }

    /**
     * 按权重分配策略
     * @param <K>
     * @param <V>
     */
    public static class WeightRandomStrategy<K, V extends Number> extends ConnectionUsedStrategy {
        private TreeMap<Double, K> weightMap = new TreeMap<>();

        public WeightRandomStrategy(List<Pair<K, V>> list) {
            for (Pair<K, V> pair : list) {
                double lastWeight = this.weightMap.size() == 0 ? 0 : this.weightMap.lastKey();
                this.weightMap.put(pair.getValue().doubleValue() + lastWeight, pair.getKey());
            }
        }

        private K random() {
            double randomWeight = this.weightMap.lastKey() * Math.random();
            SortedMap<Double, K> tailMap = this.weightMap.tailMap(randomWeight, false);
            return this.weightMap.get(tailMap.firstKey());
        }

        @Override
        Number get() {
            return (Number) this.random();
        }
    }

    public static void main(String[] args) {

        List<Pair<String, Integer>> list = new ArrayList<>();
        list.add(new Pair<>("TR", 90));
        list.add(new Pair<>("TX", 10));
        WeightRandomStrategy<String, Integer> strategy = new WeightRandomStrategy<>(list);
        int a = 0, b = 0;
        for (int i = 0; i < 10000; i++) {
            switch (strategy.random()) {
                case "TR":
                    a++;
                    break;
                case "TX":
                    b++;
                    break;
                default:
                    break;
            }
        }
        System.out.println("a=" + a + ", b=" + b);
        System.out.println("a+b=" + (a + b));

    }



}
